#include <include/mainwindow.h>
#include "ui_mainwindow.h"
#include <QThread>
#include <QDateTime>
#include <QDebug>
#include <QMessageBox>
#include <include/frame_process.h>
#include <time.h>  // clock_gettime
#include <QTimer>




//extern MainWindow * w;
/**
 * @brief MainWindow::MainWindow    主界面构造函数
 * @param parent
 */
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{
    // 2.创建一个图表
    ui->setupUi(this);
    serialPort = new QSerialPort(this);

    // 扫描本机的串口，并且添加到下拉框里
    foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {
        ui->comboBox->addItem(info.portName());
    }
    // 读取数据
    connect(serialPort, SIGNAL(readyRead()), this, SLOT(readData()));

    //.cpp文件--实例化和连接信号槽
    Timer= new QTimer();
    Timer->setTimerType(Qt::PreciseTimer);  // 设置定时器类型
    connect(Timer, SIGNAL(timeout()), this, SLOT(Timer_func()));
    Timer->start(1);  // 启动定时器并设置间隔为100ms
}

int m_chartInited =0;

/**
 * @brief MainWindow::Timer_func 定时器线程
 */
void MainWindow::Timer_func()
{ // 静态指针：仅初始化一次
    chart_display();
}


/**
 * @brief MainWindow::~MainWindow 主界面析构函数
 */
MainWindow::~MainWindow()
{
    delete ui;
}

/**
 * @brief MainWindow::on_pushButton_clicked 串口配置函数
 * @param checked                           点击的信号
 */
void MainWindow::on_pushButton_clicked(bool checked)
{
    if (checked) {
        // 设置要打开的串口的名字
        serialPort->setPortName(ui->comboBox->currentText());

        // 设置波特率
        serialPort->setBaudRate(ui->comboBox_2->currentText().toInt());

        // 设置停止位
        serialPort->setStopBits(QSerialPort::StopBits(ui->comboBox_3->currentText().toInt()));

        // 设置数据位
        serialPort->setDataBits(QSerialPort::DataBits(ui->comboBox_4->currentText().toInt()));

        // 设置校验位
        switch (ui->comboBox_5->currentIndex()) {
        case 0:
            serialPort->setParity(QSerialPort::NoParity);
            break;
        case 1:
            serialPort->setParity(QSerialPort::EvenParity);
            break;
        case 2:
            serialPort->setParity(QSerialPort::OddParity);
            break;
        case 3:
            serialPort->setParity(QSerialPort::SpaceParity);
            break;
        case 4:
            serialPort->setParity(QSerialPort::MarkParity);
            break;
        default:
            break;
        }
        // 设置流控为无
        serialPort->setFlowControl(QSerialPort::NoFlowControl);

        if (!serialPort->open(QIODevice::ReadWrite)) {
            QMessageBox::about(this, "错误", "串口打开失败可能被占用了");
            return;
        }
        ui->comboBox->setEnabled(false);
        ui->comboBox_2->setEnabled(false);
        ui->comboBox_3->setEnabled(false);
        ui->comboBox_4->setEnabled(false);
        ui->comboBox_5->setEnabled(false);
        ui->pushButton->setText("关闭串口");
    } else {
        // 关闭串口
        serialPort->close();
        ui->comboBox->setEnabled(true);
        ui->comboBox_2->setEnabled(true);
        ui->comboBox_3->setEnabled(true);
        ui->comboBox_4->setEnabled(true);
        ui->comboBox_5->setEnabled(true);
        ui->pushButton->setText("打开串口");
    }
}



//循环数组结构体
typedef struct buff_left{
    int p;//数组左移指针
    int display_nember;//显示数量
    float buffer[500]={0};//循环数组


}buff_left_t, *buff_left_p;


/**
 * @brief buff_left_float  数组循环左移
 * @param buffer           传入待循环的数组
 */
void buff_left_float(buff_left_p buffer)
{

    if(buffer->p == buffer->display_nember)//0~8都有数
    {
        buffer->p = 0;
        while(++(buffer->p))
        {
            buffer->buffer[buffer->p-1]=buffer->buffer[buffer->p];
            if(buffer->p==buffer->display_nember-1)//0~7都有数
            {
                break;
            }
        }
        buffer->p=buffer->display_nember-1;
    }
}






// 将 time_t 转换为毫秒级时间戳
long long get_milliseconds(time_t timestamp) {
    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);

    // 计算：time_t 的秒数转换为毫秒，加上当前的毫秒部分
    return timestamp * 1000LL + ts.tv_nsec / 1000000;
}
// 使用示例
time_t timestamp = time(NULL);



extern struct buffer buf[1];

/**
 * @brief MainWindow::readData 串口获取数据
 */
void MainWindow::readData()
{
    Frame_DATA frame_serial;
    // 接收数据
    //获取串口读到的数据
    QByteArray data = serialPort->readAll();
    //将数据转换成const char
    uint8_t byteValue_for = static_cast<uint8_t>(data[0]);
    uint8_t byteValue_length = static_cast<uint8_t>(data[1]);
    uint8_t byteValue_data[10];
    for (int i=0;i<byteValue_length;i++)
    {
        byteValue_data[i] = static_cast<uint8_t>(data[i+2]);
    }


    //搜索'0x01'
    if(byteValue_for == 0x01)
    {
        frame_serial.data[0] = (float)(byteValue_data[0]);

        time_t timestamp = time(NULL);

        frame_serial.time = get_milliseconds(timestamp%1000);

//        qDebug() <<"ms1:" <<  get_milliseconds(frame_serial.time) << endl;

        buffer_put(buf, &frame_serial);

    }




}






/**
 * @brief MainWindow::chart_display 图表显示函数
 */
void MainWindow::chart_display()
{
    static Frame_DATA_p frame;
    frame = buffer_get(buf);
    if(frame == NULL)
        return;
    static long long s = (frame->time / 1000)%1000;
    static long long ms = (frame->time % 1000);
    static double t = s + (double)(ms * 0.001);
    static buff_left_t y_left,x_left;
    static int initialized = 0;  // 静态标志，初始值为0

    //函数内只初始化一遍
      if (!initialized)
      {
        y_left.display_nember = x_left.display_nember = 240+2;
        ALS_CHART = new QChart();  // 仅初始化一次
        ALS_X = new QValueAxis();
        ALS_Y = new QValueAxis();
        // 5.设置坐标轴的标题和显示的格式
        ALS_X->setTitleText("程序调度时间");
        ALS_Y->setTitleText("采样值");
        ALS_X->setLabelFormat("%d");
        ALS_Y->setLabelFormat("%d");
        // 设置标题的字体大小
        QFont font;
        font.setPointSize(12); // 设置为16号字体
        // 如果你想要设置字体为粗体
        font.setBold(true);
        ALS_X->setLabelsFont(font);
        font.setPointSize(12); // 设置为16号字体
        ALS_Y->setLabelsFont(font);
        // 设置xy的显示的格式
        ALS_X->setTickCount(15);
        ALS_Y->setTickCount(15);
        // 6.图表添加坐标轴
        ALS_CHART->createDefaultAxes();
        ALS_X->setLabelFormat("%.3f");  // 设置标签格式为保留1位小数
        ALS_CHART->addAxis(ALS_X, Qt::AlignBottom);
        ALS_CHART->addAxis(ALS_Y, Qt::AlignLeft);
        // 7.设置图表的标题以及图例显示是否需要
        ALS_CHART->setTitle("采样值与时间曲线");
        ALS_CHART->setTitleFont(font);
        ALS_CHART->legend()->setVisible(false);
        lineSeries =  new QLineSeries();
        QPen pen(QColor(0xFF7F00),5);
        lineSeries->setPen(pen);
        // 9.图表添加曲线
        ALS_CHART->addSeries(lineSeries);
        ALS_CHART->setMargins({1, 1, 1, 1});
        // 10.!!!!将曲线的数据与坐标轴相连！！！！注意，这个要在图表添加曲线之后
        // 附属到坐标轴上面去
        lineSeries->attachAxis(ALS_X);
        lineSeries->attachAxis(ALS_Y);
        // 11.将图表放置于图表视图
        ui->graphicsView->setChart(ALS_CHART);
        initialized = 1;  // 标记为已初始化
      }
    y_left.buffer[y_left.p] = frame->data[0];
    x_left.buffer[x_left.p] = t;
    x_left.p++;
    y_left.p++;
    buff_left_float(&y_left);
    buff_left_float(&x_left);
    lineSeries->clear();
    if(x_left.p <=  y_left.display_nember)
    {
        ALS_X->setRange(static_cast<double>(x_left.buffer[0])/1.0, static_cast<double>(x_left.buffer[0]+23.9)/1.0);
        for(int i=0;i<y_left.display_nember;i++)
        {
          x_left.buffer[i] = static_cast<double>(x_left.buffer[0]) + static_cast<double>((23.9 / 240) * i);
          lineSeries->append( static_cast<double>(x_left.buffer[i])/1.0,  y_left.buffer[i]);
        }
    }
    else
    {
     ALS_X->setRange(static_cast<double>(x_left.buffer[0])/1.0, static_cast<double>(x_left.buffer[x_left.p])/1.0);
     for(int i=0;i<y_left.display_nember;i++)
     {
       lineSeries->append( static_cast<double>(x_left.buffer[i])/1.0,  y_left.buffer[i]);
     }
    }
    ALS_Y->setRange(0, 0xff);
}











